//
// TcpServer.cpp
//
// $Id: //poco/1.4/Net/src/TcpServer.cpp#1 $
//
// Library: Net
// Package: TcpServer
// Module:  TcpServer
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#include "Poco/Net/TcpServer.h"
#include "Poco/Net/TcpServerDispatcher.h"
#include "Poco/Net/TcpServerConnection.h"
#include "Poco/Net/TcpServerConnectionFactory.h"
#include "Poco/Timespan.h"
#include "Poco/Exception.h"
#include "Poco/ErrorHandler.h"


using Poco::ErrorHandler;


namespace Poco {
namespace Net {


TcpServer::TcpServer(TcpServerConnectionFactory* pFactory, Poco::UInt16 portNumber, TcpServerParams* pParams):
	m_socket(ServerSocket(portNumber)),
	m_thread(threadName(m_socket)),
	m_stopped(true)
{	
	Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool();
	if (pParams)
	{
		int toAdd = pParams->getMaxThreads() - pool.capacity();
		if (toAdd > 0) pool.addCapacity(toAdd);
	}
	m_pDispatcher = new TcpServerDispatcher(pFactory, pool, pParams);
	
}


TcpServer::TcpServer(TcpServerConnectionFactory* pFactory, const ServerSocket& socket, TcpServerParams* pParams):
	m_socket(socket),
	m_thread(threadName(socket)),
	m_stopped(true)
{
	Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool();
	if (pParams)
	{
		int toAdd = pParams->getMaxThreads() - pool.capacity();
		if (toAdd > 0) pool.addCapacity(toAdd);
	}
	m_pDispatcher = new TcpServerDispatcher(pFactory, pool, pParams);
}


TcpServer::TcpServer(TcpServerConnectionFactory* pFactory, Poco::ThreadPool& threadPool, const ServerSocket& socket, TcpServerParams* pParams):
	m_socket(socket),
	m_pDispatcher(new TcpServerDispatcher(pFactory, threadPool, pParams)),
	m_thread(threadName(socket)),
	m_stopped(true)
{
}


TcpServer::~TcpServer()
{
	try
	{
		stop();
		m_pDispatcher->release();
	}
	catch (...)
	{
		poco_unexpected();
	}
}


const TcpServerParams& TcpServer::params() const
{
	return m_pDispatcher->params();
}


void TcpServer::start()
{
	poco_assert (m_stopped);

	m_stopped = false;
	m_thread.start(*this);
}

	
void TcpServer::stop()
{
	if (!m_stopped)
	{
		m_stopped = true;
		m_thread.join();
		m_pDispatcher->stop();
	}
}

/// echo connection run in a thread mode
void TcpServer::run()
{
	while (!m_stopped)
	{
		Poco::Timespan timeout(250000);
		if (m_socket.poll(timeout, Socket::SELECT_READ))
		{
			try
			{
				int fd = m_socket.acceptConnection();
				// enabe nodelay per default: OSX really needs that
				Socket::setNoDelay(fd,true);
				m_pDispatcher->enqueue(fd);
			}
			catch (Poco::Exception& exc)
			{
				ErrorHandler::handle(exc);
			}
			catch (std::exception& exc)
			{
				ErrorHandler::handle(exc);
			}
			catch (...)
			{
				ErrorHandler::handle();
			}
		}
	}
}


int TcpServer::currentThreads() const
{
	return m_pDispatcher->currentThreads();
}

int TcpServer::maxThreads() const
{
	return m_pDispatcher->maxThreads();
}

	
int TcpServer::totalConnections() const
{
	return m_pDispatcher->totalConnections();
}


int TcpServer::currentConnections() const
{
	return m_pDispatcher->currentConnections();
}


int TcpServer::maxConcurrentConnections() const
{
	return m_pDispatcher->maxConcurrentConnections();
}

	
int TcpServer::queuedConnections() const
{
	return m_pDispatcher->queuedConnections();
}


int TcpServer::refusedConnections() const
{
	return m_pDispatcher->refusedConnections();
}


std::string TcpServer::threadName(const ServerSocket& socket)
{
	std::string name("TcpServer: ");
	name.append(socket.address().toString());
	return name;

}


} } // namespace Poco::Net
